Coverage Report

Created: 2025-05-07 21:06

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
D:\a\tools.proto\tools.proto\dynamic\src\field\primitive\core.rs
Line
Count
Source
1
// Copyright (c) 2025, BlockProject 3D
2
//
3
// All rights reserved.
4
//
5
// Redistribution and use in source and binary forms, with or without modification,
6
// are permitted provided that the following conditions are met:
7
//
8
//     * Redistributions of source code must retain the above copyright notice,
9
//       this list of conditions and the following disclaimer.
10
//     * Redistributions in binary form must reproduce the above copyright notice,
11
//       this list of conditions and the following disclaimer in the documentation
12
//       and/or other materials provided with the distribution.
13
//     * Neither the name of BlockProject 3D nor the names of its contributors
14
//       may be used to endorse or promote products derived from this software
15
//       without specific prior written permission.
16
//
17
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
21
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29
use bp3d_protoc::compiler::structure::{Field, FieldRaw, FieldView, FixedFieldType};
30
use bp3d_protoc::model::protocol::Endianness;
31
use crate::field::codec::{BitCodecBE, BitCodecLE, ByteCodecBE, ByteCodecLE, Codec};
32
use crate::field::primitive::{PrimitiveType, Value};
33
use crate::field::primitive::transform::{Float32Transform, Float64Transform, FloatTransform, NoneTransform, RawTransform, SignedTransform, ViewTransform};
34
35
struct Primitive<C: Codec, TRaw: RawTransform, TView: ViewTransform> {
36
    codec: C,
37
    raw: TRaw,
38
    view: TView,
39
}
40
41
impl<C: Codec, TRaw: RawTransform, TView: ViewTransform> Primitive<C, TRaw, TView> {
42
16
    pub fn new(codec: C, raw: TRaw, view: TView) -> Self {
43
16
        Self {
44
16
            codec,
45
16
            raw,
46
16
            view
47
16
        }
48
16
    }
49
}
50
51
impl<C: Codec, TRaw: RawTransform, TView: ViewTransform> PrimitiveType for Primitive<C, TRaw, TView> {
52
42
    fn get_bin(&self, bytes: &[u8]) -> u64 {
53
42
        self.codec.read(bytes)
54
42
    }
55
56
15
    fn set_bin(&self, bytes: &mut [u8], bits: u64) {
57
15
        self.codec.write(bytes, bits);
58
15
    }
59
60
37
    fn get_raw(&self, bytes: &[u8]) -> Value {
61
37
        self.raw.bits_to_raw(self.get_bin(bytes))
62
37
    }
63
64
15
    fn set_raw(&self, bytes: &mut [u8], raw: Value) {
65
15
        self.set_bin(bytes, self.raw.raw_to_bits(raw));
66
15
    }
67
68
37
    fn get(&self, bytes: &[u8]) -> Value {
69
37
        self.view.raw_to_view(self.get_raw(bytes))
70
37
    }
71
72
14
    fn set(&self, bytes: &mut [u8], value: Value) {
73
14
        self.set_raw(bytes, self.view.view_to_raw(value));
74
14
    }
75
}
76
77
enum Raw {
78
    Signed(SignedTransform),
79
    Float32(Float32Transform),
80
    Float64(Float64Transform),
81
    None(NoneTransform)
82
}
83
84
enum View {
85
    Float(FloatTransform),
86
    None(NoneTransform)
87
}
88
89
enum Codec1 {
90
    BitLE(BitCodecLE),
91
    BitBE(BitCodecBE),
92
    ByteLE(ByteCodecLE),
93
    ByteBE(ByteCodecBE)
94
}
95
96
16
fn get_field(codec: Codec1, raw: Raw, view: View) -> Box<dyn PrimitiveType> {
97
16
    match (codec, raw, view) {
98
0
        (Codec1::BitBE(c), Raw::None(r), View::None(v)) => Box::new(Primitive::new(c, r, v)),
99
4
        (Codec1::BitLE(c), Raw::None(r), View::None(v)) => Box::new(Primitive::new(c, r, v)),
100
6
        (Codec1::ByteLE(c), Raw::None(r), View::None(v)) => Box::new(Primitive::new(c, r, v)),
101
0
        (Codec1::ByteBE(c), Raw::None(r), View::None(v)) => Box::new(Primitive::new(c, r, v)),
102
0
        (Codec1::BitBE(c), Raw::Signed(r), View::None(v)) => Box::new(Primitive::new(c, r, v)),
103
4
        (Codec1::BitLE(c), Raw::Signed(r), View::None(v)) => Box::new(Primitive::new(c, r, v)),
104
0
        (Codec1::ByteLE(c), Raw::Signed(r), View::None(v)) => Box::new(Primitive::new(c, r, v)),
105
0
        (Codec1::ByteBE(c), Raw::Signed(r), View::None(v)) => Box::new(Primitive::new(c, r, v)),
106
0
        (Codec1::BitBE(c), Raw::Float32(r), View::None(v)) => Box::new(Primitive::new(c, r, v)),
107
0
        (Codec1::BitLE(c), Raw::Float32(r), View::None(v)) => Box::new(Primitive::new(c, r, v)),
108
0
        (Codec1::ByteLE(c), Raw::Float32(r), View::None(v)) => Box::new(Primitive::new(c, r, v)),
109
0
        (Codec1::ByteBE(c), Raw::Float32(r), View::None(v)) => Box::new(Primitive::new(c, r, v)),
110
0
        (Codec1::BitBE(c), Raw::Float64(r), View::None(v)) => Box::new(Primitive::new(c, r, v)),
111
0
        (Codec1::BitLE(c), Raw::Float64(r), View::None(v)) => Box::new(Primitive::new(c, r, v)),
112
0
        (Codec1::ByteLE(c), Raw::Float64(r), View::None(v)) => Box::new(Primitive::new(c, r, v)),
113
0
        (Codec1::ByteBE(c), Raw::Float64(r), View::None(v)) => Box::new(Primitive::new(c, r, v)),
114
0
        (Codec1::BitBE(c), Raw::None(r), View::Float(v)) => Box::new(Primitive::new(c, r, v)),
115
2
        (Codec1::BitLE(c), Raw::None(r), View::Float(v)) => Box::new(Primitive::new(c, r, v)),
116
0
        (Codec1::ByteLE(c), Raw::None(r), View::Float(v)) => Box::new(Primitive::new(c, r, v)),
117
0
        (Codec1::ByteBE(c), Raw::None(r), View::Float(v)) => Box::new(Primitive::new(c, r, v)),
118
0
        (Codec1::BitBE(c), Raw::Signed(r), View::Float(v)) => Box::new(Primitive::new(c, r, v)),
119
0
        (Codec1::BitLE(c), Raw::Signed(r), View::Float(v)) => Box::new(Primitive::new(c, r, v)),
120
0
        (Codec1::ByteLE(c), Raw::Signed(r), View::Float(v)) => Box::new(Primitive::new(c, r, v)),
121
0
        (Codec1::ByteBE(c), Raw::Signed(r), View::Float(v)) => Box::new(Primitive::new(c, r, v)),
122
0
        (Codec1::BitBE(c), Raw::Float32(r), View::Float(v)) => Box::new(Primitive::new(c, r, v)),
123
0
        (Codec1::BitLE(c), Raw::Float32(r), View::Float(v)) => Box::new(Primitive::new(c, r, v)),
124
0
        (Codec1::ByteLE(c), Raw::Float32(r), View::Float(v)) => Box::new(Primitive::new(c, r, v)),
125
0
        (Codec1::ByteBE(c), Raw::Float32(r), View::Float(v)) => Box::new(Primitive::new(c, r, v)),
126
0
        (Codec1::BitBE(c), Raw::Float64(r), View::Float(v)) => Box::new(Primitive::new(c, r, v)),
127
0
        (Codec1::BitLE(c), Raw::Float64(r), View::Float(v)) => Box::new(Primitive::new(c, r, v)),
128
0
        (Codec1::ByteLE(c), Raw::Float64(r), View::Float(v)) => Box::new(Primitive::new(c, r, v)),
129
0
        (Codec1::ByteBE(c), Raw::Float64(r), View::Float(v)) => Box::new(Primitive::new(c, r, v))
130
    }
131
16
}
132
133
/// Attempts to construct a [PrimitiveType] from a structure [Field], returns [None] when the field
134
/// cannot be represented a [PrimitiveType]. A value of [None] is typically returned when the field is
135
/// an enum or is not fixed.
136
10
pub fn from_field(field: &Field) -> Option<Box<dyn PrimitiveType>> {
137
10
    let fixed = field.ty.as_fixed()
?0
;
138
10
    let raw = match fixed.raw {
139
        FieldRaw::Transmute => {
140
0
            if fixed.raw_type.is_signed() {
  Branch (140:16): [Folded - Ignored]
  Branch (140:16): [True: 0, False: 0]
141
0
                Raw::Signed(SignedTransform { max_positive: 2u64.pow(fixed.raw_type.get_aligned_bit_size() as u32 - 1) - 1 })
142
0
            } else if fixed.raw_type == FixedFieldType::Float32 {
  Branch (142:23): [Folded - Ignored]
  Branch (142:23): [True: 0, False: 0]
143
0
                Raw::Float32(Float32Transform)
144
0
            } else if fixed.raw_type == FixedFieldType::Float64 {
  Branch (144:23): [Folded - Ignored]
  Branch (144:23): [True: 0, False: 0]
145
0
                Raw::Float64(Float64Transform)
146
            } else {
147
0
                Raw::None(NoneTransform)
148
            }
149
        },
150
4
        FieldRaw::SignedCast(max_positive) => Raw::Signed(SignedTransform { max_positive: max_positive as _ }),
151
6
        FieldRaw::None => Raw::None(NoneTransform)
152
    };
153
10
    let view = match fixed.view {
154
2
        FieldView::Float { a, b, a_inv, b_inv } => View::Float(FloatTransform {
155
2
            a,
156
2
            b,
157
2
            a_inv,
158
2
            b_inv,
159
2
        }),
160
0
        FieldView::Enum(_) => return None,
161
8
        _ => View::None(NoneTransform)
162
    };
163
10
    let codec = match (fixed.endianness, (field.loc.bit_size % 8) == 0) {
164
0
        (Endianness::Little, true) => Codec1::ByteLE(ByteCodecLE),
165
0
        (Endianness::Big, true) => Codec1::ByteBE(ByteCodecBE),
166
10
        (Endianness::Little, false) => Codec1::BitLE(BitCodecLE::new(field.loc.bit_offset, field.loc.bit_size)),
167
0
        (Endianness::Big, false) => Codec1::BitBE(BitCodecBE::new(field.loc.bit_offset, field.loc.bit_size)),
168
    };
169
10
    Some(get_field(codec, raw, view))
170
10
}
171
172
/// Creates a [PrimitiveType] directly from a [FixedFieldType] and a field [Endianness].
173
/// This function does not support loading from bit fields.
174
///
175
/// # Arguments
176
///
177
/// * `ty`: the type of the field.
178
/// * `endianness`: the endianness of the field.
179
///
180
/// returns: Box<dyn PrimitiveType, Global>
181
6
pub fn from_fixed_field_type(ty: FixedFieldType, endianness: Endianness) -> Box<dyn PrimitiveType> {
182
6
    let codec = match endianness {
183
6
        Endianness::Little => Codec1::ByteLE(ByteCodecLE),
184
0
        Endianness::Big => Codec1::ByteBE(ByteCodecBE),
185
    };
186
6
    let raw = if ty.is_signed() {
  Branch (186:18): [Folded - Ignored]
  Branch (186:18): [True: 0, False: 6]
187
0
        Raw::Signed(SignedTransform { max_positive: 2u64.pow(ty.get_aligned_bit_size() as u32 - 1) - 1 })
188
6
    } else if ty == FixedFieldType::Float32 {
  Branch (188:15): [Folded - Ignored]
  Branch (188:15): [True: 0, False: 6]
189
0
        Raw::Float32(Float32Transform)
190
6
    } else if ty == FixedFieldType::Float64 {
  Branch (190:15): [Folded - Ignored]
  Branch (190:15): [True: 0, False: 6]
191
0
        Raw::Float64(Float64Transform)
192
    } else {
193
6
        Raw::None(NoneTransform)
194
    };
195
6
    let view = View::None(NoneTransform);
196
6
    get_field(codec, raw, view)
197
6
}